package com.hm.cms.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.hm.cms.auto.SystemEnvConfigProperties;
import com.hm.cms.auto.su.BaseDomain;
import com.hm.cms.auto.su.R.RedisKey;
import com.hm.cms.domain.QVisitIpStatisticsDomain;
import com.hm.cms.domain.VisitIpHistoryDomain;
import com.hm.cms.domain.VisitIpStatisticsDomain;
import com.hm.cms.repository.VisitIpHistoryRepository;
import com.hm.cms.repository.VisitIpStatisticsRepository;
import com.hm.common.redis.jedis.JedisFactory;
import com.hm.common.redis.jedis.su.JedisHandler;
import com.hm.common.redis.jedis.su.JedisHandlerSupport;
import com.hm.common.util.CommonUtil;
import com.hm.common.util.DateUtil;
import com.mongodb.AggregationOutput;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

/**
 * @author shishun.wang
 * @date 下午5:35:51 2017年11月16日
 * @version 1.0
 * @describe
 */
@Service
public class VisitIpStatisticsServiceImpl implements VisitIpStatisticsService {

	@Autowired
	private VisitIpStatisticsRepository visitIpStatisticsRepository;

	@Autowired
	private VisitIpHistoryRepository visitIpHistoryRepository;

	@Autowired
	private MongoTemplate mongoTemplate;

	@Autowired
	private SystemEnvConfigProperties systemEnvConfigProperties;

	@Autowired
	private JedisHandlerSupport jedisHandler;

	@Async
	@Override
	public void saveVisitIpStatistics(String ip, String uri) {
		this.saveVisitIpHistory(ip, uri);
		String visitDate = DateUtil.now4yyyyMMdd();

		QVisitIpStatisticsDomain qVisitIpStatisticsDomain = QVisitIpStatisticsDomain.visitIpStatisticsDomain;
		VisitIpStatisticsDomain ipStatistics = visitIpStatisticsRepository.findOne(qVisitIpStatisticsDomain.ip.eq(ip).and(qVisitIpStatisticsDomain.visitDate.eq(visitDate)));
		if (CommonUtil.isNotEmpty(ipStatistics)) {
			refreshVisitIpStatisticsAccessCount(ip, visitDate);

			if (ipStatistics.getAccessCount() > systemEnvConfigProperties.getMaxVisitCount()) {
				jedisHandler.executeCommand(new JedisHandler() {

					@Override
					public Object handler(JedisFactory jedis) {
						String key = RedisKey.MAX_VISIT_COUNT + ":" + ip;
						Object value = jedis.get(key);
						if (CommonUtil.isEmpty(value)) {
							jedis.set(key, 24 * 60 * 60, "true");
						}
						return null;
					}
				});
			}

			return;
		}

		VisitIpStatisticsDomain statisticsDomain = new VisitIpStatisticsDomain();
		BaseDomain.initBaseInfo(statisticsDomain);
		statisticsDomain.setReqUri(uri);
		statisticsDomain.setIp(ip);
		statisticsDomain.setVisitTime(statisticsDomain.getCreateTime());
		statisticsDomain.setVisitDate(visitDate);
		statisticsDomain.setAccessCount(1);
		visitIpStatisticsRepository.save(statisticsDomain);
	}

	@Async
	private void saveVisitIpHistory(String ip, String uri) {
		VisitIpHistoryDomain visitIpHistory = new VisitIpHistoryDomain();
		BaseDomain.initBaseInfo(visitIpHistory);
		visitIpHistory.setReqUri(uri);
		visitIpHistory.setIp(ip);
		visitIpHistory.setVisitTime(DateUtil.now4yyyyMMddhhmm());
		visitIpHistoryRepository.save(visitIpHistory);
	}

	/**
	 * 刷新ip地址，递增
	 * 
	 * @param ip
	 * @param visitDate
	 */
	private void refreshVisitIpStatisticsAccessCount(String ip, String visitDate) {
		mongoTemplate.updateMulti(new Query(Criteria.where("ip").is(ip)), new Update().inc("access_count", 1), VisitIpStatisticsDomain.class);
	}

	@Override
	public Map<String, Object> webPageTrafficStatisticsReports() {
		Date now = new Date();
		String startTime = DateUtil.yyyyMMdd(DateUtil.getCurrentCustomerDay(now, -365));
		String endTime = DateUtil.yyyyMMdd(now);

		List<DBObject> pipeline = new ArrayList<DBObject>();
		{
			BasicDBList items = new BasicDBList();
			{
				items.add(new BasicDBObject("visit_date", new BasicDBObject("$gte", startTime)));
				items.add(new BasicDBObject("visit_date", new BasicDBObject("$lte", endTime)));
			}
			DBObject match = new BasicDBObject("$match", new BasicDBObject("$and", items));
			pipeline.add(match);

			DBObject project = new BasicDBObject("$project", new BasicDBObject("_id", 1).append("access_count", 1).append("visit_date", 1));
			pipeline.add(project);

			DBObject group = new BasicDBObject("$group", new BasicDBObject("_id", "$visit_date").append("access_count", new BasicDBObject("$sum", "$access_count")));
			pipeline.add(group);

			DBObject sort = new BasicDBObject("$sort", new BasicDBObject("_id", 1));
			pipeline.add(sort);
		}

		
		Map<String, Object> vo = new LinkedHashMap<String, Object>();
		AggregationOutput output = mongoTemplate.getCollection(mongoTemplate.getCollectionName(VisitIpStatisticsDomain.class)).aggregate(pipeline);
		
		List<String> x = new LinkedList<String>();
		List<Object> y = new LinkedList<Object>();
		for (Iterator<DBObject> it = output.results().iterator(); it.hasNext();) {
			BasicDBObject dbo = (BasicDBObject) it.next();
			
			x.add(dbo.getString("_id"));
			y.add(dbo.getLong("access_count"));
		}

		vo.put("x", x);
		vo.put("y", y);
		
		return vo;
	}
}
